﻿#include "serial_file_com_nonebuf.h"
#include <stdio.h>
#include <fcntl.h>
#include "cross_com.h"
CSerialFileComNobuf::CSerialFileComNobuf()
{
	m_fileSize = SIZE_MB(128);
	m_baseLBA  = 2048;

	m_bRecordWtTime = true;
	m_access_mod = -1;
	m_pLock = NULL;
#ifndef _WIN32
	m_pLock = new pthread_mutex_t; 		//互斥锁
	pthread_mutexattr_t mutexAttr;
	pthread_mutexattr_init(&mutexAttr);
	pthread_mutexattr_settype(&mutexAttr, PTHREAD_MUTEX_RECURSIVE);
	pthread_mutex_init((pthread_mutex_t*)m_pLock,&mutexAttr);
	pthread_mutexattr_destroy(&mutexAttr);
	m_fd          = -1;
#else
	m_pLock       =  new CRITICAL_SECTION;;
	m_fd          = INVALID_HANDLE_VALUE;
#endif

	m_align_buf = NULL;
	m_cache_buf = NULL;
	m_cache_pos   = 0;
	m_cur_offset  = 0;
	m_sec_size    = SIZE_4KB;
	m_lastRet     = 0;
	memset(m_storage_file,0,60); 
    m_pCacheBuf   = new char[m_sec_size];
}

CSerialFileComNobuf::~CSerialFileComNobuf()
{
	delete [] m_pCacheBuf;
}
int CSerialFileComNobuf::Open(void * file,uint64_t fileLBA, uint32_t fileSize, int acess_mod)
{
	char file_name[260] = {0};
	bool bCreate = false;
	int err = 0;

	if(NULL == file)
	{
		TRACE_ERR("NO device.\n");
		return ERR_FILE_NOOPEN;
	};
	Lock();
	strcpy(file_name,(char*)file);
	
	if( 0 == memcmp((char*)file,m_storage_file,strlen((char*)file)) && 
		acess_mod == m_access_mod)
	{
		TRACE("File is opened %s file_name.\n",file_name);
		Unlock();
		return ERR_FILE_OPENED;
	}

	strcpy(m_storage_file,(char*)file);

#ifdef _WIN32
	if(0 == access((char*)file,0))
	{
		if(acess_mod == SCSI_RDONLY)
		{
			m_fd =  CreateFile((char*)file,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
		}
		else
			m_fd = CreateFile((char*)file,GENERIC_WRITE|FILE_SHARE_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
		bCreate = true;
	}
	else
	{
		m_fd = CreateFile((char*)file,GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
	}
#else
	if(0 == access(file_name,0))
	{
		if(acess_mod == SCSI_RDONLY)
		{
			m_fd = open(file_name,O_RDONLY);

		}
		else
		{
			m_fd = open(file_name,O_RDWR);
			if( -1 == m_fd)
			{
				m_fd = open(file_name,O_WRONLY);
			}
		}
		bCreate = true;
	}
	else
	{  //首次打开
		m_fd = open(file_name,O_RDWR|O_CREAT);
	}
#endif

#ifdef _WIN32
	if( INVALID_HANDLE_VALUE == m_fd )
#else
	if( -1 == m_fd )
#endif // _WIN32
	{
#ifdef _WIN32
		err = GetLastErr();
#else
		err = errno;
#endif
		TRACE("Error open %s  errno %d .\n",file_name,errno);
		Unlock();
		return ERR_FILE_OPEN;
	}
	
	m_baseLBA    = fileLBA;
	m_fileSize   = fileSize;
	if(acess_mod == SCSI_RDONLY)
	{
		m_fileSize = get_file_sie(file_name);
	}
	m_cur_offset = 0;
	m_status     = FILE_NORMAL;
	m_access_mod = acess_mod;
	if(m_bRecordWtTime)
	{
		SetLastWriteTm();
	}
	m_lastRet = 0;
	Unlock();
	
	return 0;
}

// int CSerialFileComNobuf::Open(void * file,uint64_t fileLBA, uint32_t fileSize, int acess_mod)
// {
// 	char file_name[260] = {0};
// 	bool bCreate = false;
// 	int err = 0;
// 
// 	if(NULL == file)
// 	{
// 		TRACE_ERR("NO device.\n");
// 		return ERR_FILE_NOOPEN;
// 	};
// 	Lock();
// 	strcpy(file_name,(char*)file);
// 	
// 	if( 0 == strcmp(file_name,m_storage_file) && 
// 		acess_mod == m_access_mod)
// 	{
// 		TRACE("File is opened %s file_name.\n",file_name);
// 		Unlock();
// 		return ERR_FILE_OPENED;
// 	}
// 
// 	strcpy(m_storage_file,file_name);
// 
// #ifdef _WIN32
// 	if(0 == access(file_name,0))
// 	{
// 		if(acess_mod == SCSI_RDONLY)
// 		{
// 			m_fd =  CreateFile(file_name,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
// 		}
// 		else
// 			m_fd = CreateFile(file_name,GENERIC_WRITE|FILE_SHARE_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
// 		bCreate = true;
// 	}
// 	else
// 	{
// 		m_fd = CreateFile(file_name,GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
// 	}
// #else
// 	if(0 == access(file_name,0))
// 	{
// 		if(acess_mod == SCSI_RDONLY)
// 		{
// 			m_fd = open(file_name,O_RDONLY);
// 
// 		}
// 		else
// 		{
// 			m_fd = open(file_name,O_RDWR);
// 			if( -1 == m_fd)
// 			{
// 				m_fd = open(file_name,O_WRONLY);
// 			}
// 		}
// 		bCreate = true;
// 	}
// 	else
// 	{  //首次打开
// 		m_fd = open(file_name,O_RDWR|O_CREAT);
// 	}
// #endif
// 
// #ifdef _WIN32
// 	if( INVALID_HANDLE_VALUE == m_fd )
// #else
// 	if( -1 == m_fd )
// #endif // _WIN32
// 	{
// #ifdef _WIN32
// 		err = GetLastErr();
// #else
// 		err = errno;
// #endif
// 		TRACE("Error open %s  errno %d .\n",file_name,errno);
// 		Unlock();
// 		return ERR_FILE_OPEN;
// 	}
// 	
// 	m_baseLBA    = fileLBA;
// 	m_fileSize   = fileSize;
// 	if(acess_mod == SCSI_RDONLY)
// 	{
// 		m_fileSize = get_file_sie(file_name);
// 	}
// 	m_cur_offset = 0;
// 	m_status     = FILE_NORMAL;
// 	m_access_mod = acess_mod;
// 	if(m_bRecordWtTime)
// 	{
// 		SetLastWriteTm();
// 	}
// 	m_lastRet = 0;
// 	Unlock();
// 	
// 	return 0;
// }

int CSerialFileComNobuf::ReOpen()
{
#ifdef _WIN32
	if(INVALID_HANDLE_VALUE != m_fd)
	{
		CloseHandle(m_fd);
		m_fd =INVALID_HANDLE_VALUE;
	}
#else
	if(-1 != m_fd)
	{
		close(m_fd);
		m_fd = -1;
	}
#endif

	return Open(m_storage_file,m_baseLBA,m_fileSize,m_access_mod);
}


int CSerialFileComNobuf::Close()
{
	Lock();

	m_baseLBA    = 0;
	m_fileSize   = 0;
	m_cur_offset = 0;
	m_status     = FILE_CLOSED;
	m_access_mod = SCSI_CLOSED;
#ifdef _WIN32
	if(INVALID_HANDLE_VALUE != m_fd)
	{
		CloseHandle(m_fd);
		m_fd =INVALID_HANDLE_VALUE;
	}
#else
	if(-1 != m_fd)
	{
		close(m_fd);
		m_fd = -1;
	}
#endif

	Unlock();

	return 0;
}

int CSerialFileComNobuf::Seek(int32_t offset,int whence)
{
    int  ret = 0;
	if(offset < 0)
	{
		goto ERR_OUT;
	}

	if((uint32_t)abs(offset) > m_fileSize )
	{
		goto ERR_OUT;
	}

#ifdef _WIN32
	if( INVALID_HANDLE_VALUE == m_fd )
#else
	if( -1 == m_fd )
#endif // _WIN32
	{
		return ERR_FILE_NOOPEN;
	}

#ifdef _WIN32
	ret = SetFilePointer(m_fd,offset,NULL,whence);
#else
	ret = lseek(m_fd,offset,whence);
#endif

	if(offset != ret )
	{
		return ERR_SEEK_FAIL;
	}

	switch(whence)
	{
	case SCSI_SEEK_END:
		m_cur_offset = m_fileSize - 1;
		break;

	case SCSI_SEEK_CUR:
		if(offset < 0)
		{
			if((uint32_t)abs(offset) > m_cur_offset )
			{
				goto ERR_OUT;
			}
			m_cur_offset = m_cur_offset - abs(offset);
		}
		else
		{
			if(IsOverFileArea(offset))
			{
				goto ERR_OUT;
			}
			m_cur_offset = m_cur_offset + offset;
		}
		break;

	case SCSI_SEEK_SET:

		if(offset < 0)
		{
			goto ERR_OUT;
		}
		else if((uint32_t)offset > m_fileSize )
		{
			goto ERR_OUT;
		}
		else
		{
			m_cur_offset =(uint32_t)offset;
		}
		break;

	default:
		TRACE_ERR("Error param.\n");
		goto ERR_OUT;
		break;
	}
	m_cur_offset = offset;

	return 0;
ERR_OUT:
	return ERR_SEEK_FAIL;
}

int CSerialFileComNobuf::Read(uchar_t * pBuf, uint32_t dataSize, bool bLock)
{
#ifdef _WIN32
	if( INVALID_HANDLE_VALUE == m_fd )
#else
	if( -1 == m_fd )
#endif // _WIN32
	{
		return ERR_NO_DEVICE;
	}
#ifdef _WIN32
	BOOL bRet = FALSE;
	DWORD written = 0;
	bRet = ReadFile(m_fd,pBuf,dataSize,&written,NULL);
	if( !bRet)
	{
		return ERR_READ_FAIL;
	}
#else
	if(dataSize != read(m_fd,pBuf,dataSize))
	{
		return ERR_READ_FAIL;
	}
#endif
	m_cur_offset  += dataSize;
	return dataSize;
}

int CSerialFileComNobuf::Write(uchar_t * pBuf, uint32_t dataSize, bool bLock)
{
#ifdef _WIN32
	if( INVALID_HANDLE_VALUE == m_fd )
#else
	if( -1 == m_fd )
#endif // _WIN32
	{
		return ERR_NO_DEVICE;
	}
#ifdef _WIN32
	BOOL bRet = FALSE;
	DWORD written = 0;
	bRet = WriteFile(m_fd,pBuf,dataSize,&written,NULL);
	if( !bRet)
	{
		return ERR_WRITE_FAIL;
	}
#else
	if(dataSize != write(m_fd,pBuf,dataSize))
	{
		return ERR_WRITE_FAIL;
	}
#endif
	m_cur_offset  += dataSize;
	return dataSize;
}

int CSerialFileComNobuf::ReadPos(uint32_t offset, uchar_t * pBuf, uint32_t dataSize, bool bLock)
{
	int ret = 0;
	int nRet= 0;
	int diff = 0;
#ifdef _WIN32
	if( INVALID_HANDLE_VALUE == m_fd )
#else
	if( -1 == m_fd )
#endif // _WIN32
	{
		return ERR_NO_DEVICE;
	}

#ifdef _WIN32
	BOOL bRet = FALSE;
	DWORD written = 0;

	SetFilePointer(m_fd,offset,NULL,FILE_BEGIN);
	bRet = ReadFile(m_fd,pBuf,dataSize,&written,NULL);
	if(!bRet)
	{
		TRACE("File %s WriteCachePos data fail. offset %d dataSize %d \n",m_storage_file,offset,dataSize);
		return ERR_WRITE_FAIL;
	}
	ret = written;
#else
	nRet =  lseek(m_fd,offset,SEEK_SET);
	if(offset != nRet)
	{
		TRACE("File %s ReadPos data fail. offset %d dataSize %d nRet %d \n",m_storage_file,offset,dataSize,nRet);
		nRet = lseek(m_fd,offset,SEEK_SET);
		// 两次都定位失败
		if(nRet != offset) //尝试使用其它方法
		{
			m_cur_offset =  lseek(m_fd,0,SEEK_CUR);
			diff = m_cur_offset - offset;
			nRet =   lseek(m_fd,offset,SEEK_CUR); //fseek(m_pFile,diff,SEEK_CUR);
			if(nRet != 0)
			{
				ret = errno;
				ReOpen();
				nRet = lseek(m_fd,offset,SEEK_SET); //fseek(m_pFile,offset,SEEK_SET);
				if(nRet != 0)
				{
					TRACE_ERR("SEEK_CUR error destoffset %d  diff %d m_cur_offset %d  errno %d . \n",offset,diff,m_cur_offset,ret);
					return ERR_SEEK_FAIL;
				}
			}
		}
	}

	ret = read(m_fd,pBuf,(size_t)dataSize);
	if( dataSize != ret)
	{
		ret = errno;
		TRACE("File %s ReadPos data fail. offset %d dataSize %d nRet %d \n",m_storage_file,offset,dataSize,nRet);
		return ERR_READ_FAIL;
	}
#endif
	m_cur_offset = offset + dataSize;
	return dataSize;
}

int CSerialFileComNobuf::WritePos(uint32_t offset, uchar_t * pBuf, uint32_t dataSize, bool bLock)
{
#ifdef _WIN32
	if( INVALID_HANDLE_VALUE == m_fd )
#else
	if( -1 == m_fd )
#endif // _WIN32
	{
		return ERR_NO_DEVICE;
	}
	int ret = 0;
	int diff = 0;
	int nRet = 0;
	uint32_t curOffset = 0;

#ifdef _WIN32
	BOOL bRet = FALSE;
	DWORD written = 0;

	SetFilePointer(m_fd,offset,NULL,FILE_BEGIN);
	bRet = WriteFile(m_fd,pBuf,dataSize,&written,NULL);
	if(!bRet)
	{
		TRACE("File %s WriteCachePos data fail. offset %d dataSize %d \n",m_storage_file,offset,dataSize);
		return ERR_WRITE_FAIL;
	}
	ret = written;
#else
	nRet =  lseek(m_fd,offset,SEEK_SET);
	if(offset != nRet)
	{
		ret = errno;
		TRACE("File %s ReadPos data fail. offset %d dataSize %d nRet  %d errno %d \n",m_storage_file,offset,dataSize,nRet,ret);
		nRet = lseek(m_fd,offset,SEEK_SET);
		// 两次都定位失败
		if(nRet != offset ) //尝试使用其它方法
		{
            TRACE_ERR("SEEK_CUR error destoffset %d  diff %d m_cur_offset %d ret %d . \n",offset,diff,m_cur_offset,ret);
            return ERR_SEEK_FAIL;
		}
	}

	if( dataSize != write(m_fd,pBuf,dataSize))
	{
		TRACE("File %s WriteCachePos data fail. offset %d dataSize %d \n",m_storage_file,offset,dataSize);
		return ERR_WRITE_FAIL;
	}
#endif
	return dataSize;
}

int CSerialFileComNobuf::WriteCachePos(uint32_t offset, uchar_t * pBuf, uint32_t dataSize, bool bLock)
{
	int ret = dataSize;
#ifdef _WIN32
	if( INVALID_HANDLE_VALUE == m_fd )
#else
	if( -1 == m_fd )
#endif // _WIN32
	{
		return ERR_NO_DEVICE;
	}

#ifdef _WIN32
	BOOL bRet = FALSE;
	DWORD written = 0;

	SetFilePointer(m_fd,offset,NULL,FILE_BEGIN);
	bRet = WriteFile(m_fd,pBuf,dataSize,&written,NULL);
	if(!bRet)
	{
		TRACE("File %s WriteCachePos data fail. offset %d dataSize %d \n",m_storage_file,offset,dataSize);
		return ERR_WRITE_FAIL;
	}
	ret = written;
#else
	lseek(m_fd,offset,SEEK_SET);

	if( dataSize != write(m_fd,pBuf,dataSize))
	{
		TRACE("File %s WriteCachePos data fail. offset %d dataSize %d \n",m_storage_file,offset,dataSize);
		return ERR_WRITE_FAIL;
	}
#endif
	m_cur_offset = offset + dataSize;
	if(m_bRecordWtTime)
	{
		SetLastWriteTm();
	}

	return ret;
}

int CSerialFileComNobuf::FillTotalSpace()
{
//	int ret = lseek(m_fd,m_fileSize-1,SEEK_SET);
// 	if(ret < 0)
// 	{
// 		fclose(m_pFile);
// 		return ret;
// 	}
// 	if(fwrite("1",1,1,m_pFile) != 1)
// 	{
// 		fclose(m_pFile);
// 		return ERR_WRITE_FAIL;
// 	}
	int ret = 0;
#ifdef _WIN32
	BOOL bRet = 0;
	DWORD written = 0;

	ret = SetFilePointer(m_fd,m_fileSize-1,NULL,SEEK_SET);
	bRet = WriteFile(m_fd,"1",1,&written,NULL);
#else
	ret = lseek(m_fd,m_fileSize-1,SEEK_SET);
	write(m_fd,"1",1);
#endif

	return ret;
}


 void CSerialFileComNobuf::Flush()
 {
#ifdef _WIN32
	 if( INVALID_HANDLE_VALUE == m_fd )
#else
	 if( -1 == m_fd )
#endif // _WIN32
	 {
		 return ;
	 }
#ifdef _WIN32

#else
#endif
 }
